package com.example.component;

import com.alibaba.fastjson.JSONObject;
import com.example.config.PayBeanConfig;
import com.example.config.WechatPayApi;
import com.example.config.WechatPayConfig;
import com.example.enums.RefundEnum;
import com.example.utils.CommonUtil;
import com.example.vo.PayInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author yinxin
 * @version 1.0
 * @Description:
 * @date 2022/6/2015:37
 */
@Service
@Slf4j
public class WechatPayStrategy implements PayStrategy {

    @Autowired
    private PayBeanConfig payBeanConfig;

    @Autowired
    private WechatPayConfig payConfig;

    @Autowired
    private CloseableHttpClient wechatPayClient;

    //下单
    @Override
    public String unifieOrder(PayInfoVO payInfoVO) {
        //过期时间  RFC 3339格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
        //支付订单过期时间
        String timeExpire = sdf.format(new Date(System.currentTimeMillis() + payInfoVO.getOrderPayTimeoutMills()));

        JSONObject payObj = new JSONObject();
        JSONObject amountObj = new JSONObject();
        payObj.put("appid", payConfig.getWxPayAppid());
        payObj.put("mchid", payConfig.getMchId());
        payObj.put("out_trade_no", payInfoVO.getOutTradeNo());
        payObj.put("description", payInfoVO.getTitle());
        payObj.put("notify_url", payConfig.getCallbackUrl());
        payObj.put("time_expire", timeExpire);

        //数据库存储是double比如，100.99元，微信支付需要以分为单位
//        int amount = payInfoVO.getPayFee().multiply(BigDecimal.valueOf(100)).intValue();
        int amount = payInfoVO.getPayFee().intValue();
        amountObj.put("total", amount);//分未单位
        amountObj.put("currency", "CNY");//人民币
        payObj.put("amount", amountObj);
        //附属参数用在回调
        payObj.put("attach", "{\"accountNo\":" + payInfoVO.getAccountNo() + "}");

        String body = payObj.toJSONString();
        log.info("请求体:{}", body);

        StringEntity stringEntity = new StringEntity(body, "utf-8");
        stringEntity.setContentType("application/json");

        HttpPost httpPost = new HttpPost(WechatPayApi.NATIVE_ORDER);
        httpPost.setHeader("Accept", "application/json");
        httpPost.setEntity(stringEntity);

        String result = "";
        try (CloseableHttpResponse response = wechatPayClient.execute(httpPost);) {
            int statusCode = response.getStatusLine().getStatusCode();
            String responseStr = EntityUtils.toString(response.getEntity());
            log.info("返回码:" + statusCode + "        返回参数:" + responseStr);
            if (statusCode == HttpStatus.OK.value()) {
                JSONObject jsonObject = JSONObject.parseObject(responseStr);
                if (jsonObject.containsKey("code_url")) {
                    result = jsonObject.getString("code_url");
                }
            } else {
                log.error("微信支付响应失败:resp code={}，return body={}", statusCode, responseStr);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    //退款
    @Override
    public String refund(PayInfoVO payInfoVO) {

        String refundNo = CommonUtil.getStringNumRandom(32);
        // 请求body参数
        JSONObject refundObj = new JSONObject();
        //订单号
        refundObj.put("out_trade_no", payInfoVO.getOutTradeNo());
        //退款单编号，商户系统内部的退款单号，商户系统内部唯一，
        // 只能是数字、大小写字母_-|*@ ，同一退款单号多次请求只退一笔
        refundObj.put("out_refund_no", refundNo);
        refundObj.put("reason", payInfoVO.getRefundReason());
        refundObj.put("notify_url", payConfig.getCallbackUrl());

        JSONObject amountObj = new JSONObject();
        int amount = payInfoVO.getPayFee().multiply(BigDecimal.valueOf(100)).intValue();
        //退款金额(这里原价退款)
        amountObj.put("refund", amount);
        //实际支付的总金额
        amountObj.put("total", amount);
        amountObj.put("currency", "CNY");
        refundObj.put("amount", amountObj);
        String body = refundObj.toJSONString();
        log.info("请求参数:{}",body);

        StringEntity entity = new StringEntity(body,"utf-8");
        entity.setContentType("application/json");

        HttpPost httpPost = new HttpPost(WechatPayApi.NATIVE_REFUND_ORDER);
        httpPost.setHeader("Accept","application/json");
        httpPost.setEntity(entity);

        String result = "";
        try(CloseableHttpResponse response = wechatPayClient.execute(httpPost)){
            //响应码
            int statusCode = response.getStatusLine().getStatusCode();
            //响应体
            String responseStr = EntityUtils.toString(response.getEntity());
            log.info("申请订单退款响应码:{},响应体:{}",statusCode,responseStr);
            if(statusCode == HttpStatus.OK.value()){
                JSONObject jsonObject = JSONObject.parseObject(responseStr);
                String status = jsonObject.getString("status");
                if(RefundEnum.SUCCESS.getMsg().equals(status)){//退款成功
                    result = RefundEnum.SUCCESS.getDesc();
                }else if(RefundEnum.CLOSED.getMsg().equals(status)){//退款关闭
                    result = RefundEnum.CLOSED.getDesc();
                }else if(RefundEnum.ABNORMAL.getMsg().equals(status)){//退款异常
                    result = RefundEnum.ABNORMAL.getDesc();
                }else if(RefundEnum.PROCESSING.getMsg().equals(status)){//退款处理中
                    result = RefundEnum.PROCESSING.getDesc();
                }
            }else {
                log.error("微信退款响应失败:resp code={}，return body={}", statusCode, responseStr);
            }
        }catch (Exception e){
            log.error("微信退款异常:{}",e.getMessage());
        }
        return result;
    }

    //查状态
    @Override
    public String queryPayStatus(PayInfoVO payInfoVO) {
        String url = String.format(WechatPayApi.NATIVE_QUERY, payInfoVO.getOutTradeNo(), payConfig.getMchId());
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("Accept", "application/json");

        String result = "";
        try (CloseableHttpResponse response = wechatPayClient.execute(httpGet)) {
            //响应码
            int statusCode = response.getStatusLine().getStatusCode();
            //响应体
            String responseStr = EntityUtils.toString(response.getEntity());
            log.info("查询响应码:{},响应体:{}", statusCode, responseStr);

            if (statusCode == HttpStatus.OK.value()) {
                JSONObject jsonObject = JSONObject.parseObject(responseStr);
                if (jsonObject.containsKey("trade_state")) {
                    result = jsonObject.getString("trade_state");
                }
            } else {
                log.error("查询支付状态响应失败:{},响应体:{}", statusCode, responseStr);
            }
        } catch (Exception e) {
            log.error("微信支付响应异常:{}",e.getMessage());
        }
        return result;
    }

    //关闭订单
    @Override
    public String closeOrder(PayInfoVO payInfoVO) {

        String outTradeNo = payInfoVO.getOutTradeNo();

        JSONObject payObj = new JSONObject();
        payObj.put("mchid",payConfig.getMchId());

        String body = payObj.toJSONString();

        log.debug("请求参数:{}",body);
        //将请求参数设置到请求对象中
        StringEntity entity = new StringEntity(body,"utf-8");
        entity.setContentType("application/json");

        String url = String.format(WechatPayApi.NATIVE_CLOSE_ORDER,outTradeNo);
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("Accept","application/json");
        httpPost.setEntity(entity);

        String result = "";
        try(CloseableHttpResponse response = wechatPayClient.execute(httpPost)){
            //响应码
            int statusCode = response.getStatusLine().getStatusCode();
            log.debug("关闭订单响应码:{},无响应体",statusCode);
            if(statusCode == HttpStatus.NO_CONTENT.value()){
                result = "CLOSE_SUCCESS";
            }
        }catch (Exception e){
            log.error("微信支付响应异常:{}",e.getMessage());
        }
        return result;
    }
}
